#include "AlarmService.h"
#include "../db/DBPoll.h"
#include "../util/DateTime.h"
#include "../util/TextUtil.h"

// 数据表名称
#define SQL_DB_NAME_ALARM	"t_alarm"

// 建表语句
#define SQL_CREATE_ALARM \
"CREATE TABLE IF NOT EXISTS `t_alarm`("\
"`id` VARCHAR(64) NOT NULL comment '记录编码',"\
"`deviceId` VARCHAR(64) NOT NULL comment '设备编码',"\
"`deviceName` VARCHAR(32) default NULL comment '设备名称',"\
"`alarmTime` DATETIME default NULL comment '报警时间',"\
"`alarmType` VARCHAR(255) default NULL comment '报警类型',"\
"`alarmInfo` VARCHAR(32) default '' comment '报警描述',"\
"`count` INT(10) default 0 comment '识别数量',"\
"`upload` TINYINT(1) default 0 comment '上传状态',"\
"`uploadTime` DATETIME default NULL comment '上传时间',"\
"`uploadCount` INT default 0 comment '上传次数',"\
"`imagePath` VARCHAR(255) default NULL comment '报警图片',"\
"`imageUrl` VARCHAR(255) default NULL comment '图片地址',"\
"`uploadRecord` TINYINT(1) default 0 comment '录像上传状态',"\
"`recordPath` VARCHAR(255) default NULL comment '录像存储路径',"\
"`recordUrl` VARCHAR(255) default NULL comment '录像访问地址',"\
"`reserver1` VARCHAR(255) default NULL comment '保留字段1',"\
"`reserver2` VARCHAR(255) default NULL comment '保留字段2',"\
"primary key(`id`)"\
") ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='报警记录'"

// SQLite建表
#define SQL_CREATE_ALARM2	\
"CREATE TABLE IF NOT EXISTS `t_alarm`("\
"`id` VARCHAR(64) NOT NULL,"\
"`deviceId` VARCHAR(64) NOT NULL,"\
"`deviceName` VARCHAR(32) default NULL,"\
"`alarmTime` DATETIME default NULL,"\
"`alarmType` VARCHAR(255) default NULL,"\
"`alarmInfo` VARCHAR(32) default '',"\
"`count` INT(10) default 0,"\
"`upload` TINYINT(1) default 0,"\
"`uploadTime` DATETIME default NULL,"\
"`uploadCount` INT default 0,"\
"`imagePath` VARCHAR(255) default NULL,"\
"`imageUrl` VARCHAR(255) default NULL,"\
"`uploadRecord` TINYINT(1) default 0,"\
"`recordPath` VARCHAR(255) default NULL,"\
"`recordUrl` VARCHAR(255) default NULL,"\
"`reserver1` VARCHAR(255) default NULL,"\
"`reserver2` VARCHAR(255) default NULL,"\
"primary key(`id`)"\
")"

// 新增语句
#define SQL_INSERT_ALARM \
"insert into t_alarm(`id`, `deviceId`,`deviceName`,`alarmTime`, `alarmType`, `alarmInfo`, "\
"`count`, `upload`,`uploadCount`,`imagePath`,`imageUrl`,`uploadRecord`)"\
"values('%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s', '%s', %d)"

// 删除语句					  
#define SQL_DELETE_ALARM \
"delete from t_alarm where `id`='%s'"

// 查询语句					  
#define SQL_QUERY_ALARM \
"select * from t_alarm where `id`='%s'"

// 查询记录数		  
#define SQL_QUERY_ALARM_COUNT \
"select cout(*) from t_alarm where 1=1"

// 分页查询					  
#define SQL_QUERY_ALARM_PAGE \
"select * from t_alarm where 1=1"

// 更新语句					  
#define SQL_UPDATE_ALARM \
"update t_alarm set `uploadRecord` = 0, `recordPath`='%s', `recordUrl`='%s' where `id`='%s'"

// 更新上传状态
#define SQL_ALARM_UPLOAD \
"update t_alarm set `upload` = 1, `uploadTime`='%s' where `id`='%s'"


AlarmService::AlarmService()
{
}

AlarmService::~AlarmService()
{
}

bool AlarmService::Exist()
{
	IDbBasePtr db = DBPoll::get_mutable_instance().Pop();
	if (db)
	{
		bool ret = db->IsTableExist(SQL_DB_NAME_ALARM);
		DBPoll::get_mutable_instance().Push(db);
		return ret;
	}
	return false;
}

bool AlarmService::Create()
{
	IDbBasePtr db = DBPoll::get_mutable_instance().Pop();
	if (db)
	{
		std::string sql = db->GetDbType() == 0 ? SQL_CREATE_ALARM : SQL_CREATE_ALARM2;
		sql = TextUtil::get_mutable_instance().Ascii2Utf8(sql.c_str());
		bool ret = db->CreateTable(sql.c_str());
		DBPoll::get_mutable_instance().Push(db);
		return ret;
	}
	return false;
}

bool AlarmService::Add(AlarmInfo& item)
{
	IDbBasePtr db = DBPoll::get_mutable_instance().Pop();
	if (db)
	{
		std::string sql = boost::str(boost::format(SQL_INSERT_ALARM)
			% item.GetId() % item.GetDeviceId()
			% item.GetDeviceName() % item.GetAlarmTime().ToNormalString()
			% item.GetAlarmType() % item.GetAlarmInfo()
			% item.GetCount() % item.GetUpload()
			% item.GetUploadCount() % item.GetImagePath()
			% item.GetImageUrl() % item.GetUploadRecord());

		uint64_t id = db->Insert(sql.c_str());
		DBPoll::get_mutable_instance().Push(db);
		if (0xffffffff == id)
		{
			return false;
		}
		return true;
	}
	return false;
}

bool AlarmService::Delete(AlarmInfo& item, bool delFromDB)
{
	IDbBasePtr db = DBPoll::get_mutable_instance().Pop();
	if (db)
	{
		bool ret = false;
		if (delFromDB)
		{
			std::string sql = boost::str(boost::format(SQL_DELETE_ALARM) % item.GetId());
			ret = db->Delete(sql.c_str());
		}

		DBPoll::get_mutable_instance().Push(db);
		return ret;
	}
	return false;
}

// 查询数量
int AlarmService::Count()
{
	int count = 0;
	IDbBasePtr db = DBPoll::get_mutable_instance().Pop();
	if (db)
	{
		std::string sql = boost::str(boost::format(SQL_QUERY_ALARM_COUNT));
		bool ret = db->Query(sql.c_str());
		if (ret)
		{
			if (db->FetchNextRow())
			{
				char* v = db->GetColValue(0);
				count = std::stoi(v);
			}
			db->FreeQueryResult();
		}
		DBPoll::get_mutable_instance().Push(db);
	}
	return count;
}

int AlarmService::Count(std::string deviceId, std::string startTime, std::string endTime, std::string alarmType, std::string upload)
{
	int count = 0;
	IDbBasePtr db = DBPoll::get_mutable_instance().Pop();
	if (db)
	{
		std::string sql = boost::str(boost::format(SQL_QUERY_ALARM_COUNT));
		if (!deviceId.empty())
		{
			sql += boost::str(boost::format(" and `deviceId`='%s'") % deviceId);
		}
		if (!startTime.empty() && !endTime.empty())
		{
			sql += boost::str(boost::format(" and `alarmTime` between '%s' and '%s'") % startTime % endTime);
		}
		if (!alarmType.empty())
		{
			sql += boost::str(boost::format(" and `alarmType`='%s'") % alarmType);
		}
		if (!upload.empty())
		{
			sql += boost::str(boost::format(" and `upload`=%s") % upload);
		}
		bool ret = db->Query(sql.c_str());
		if (ret)
		{
			if (db->FetchNextRow())
			{
				char* v = db->GetColValue(0);
				count = std::stoi(v);
			}
			db->FreeQueryResult();
		}
		DBPoll::get_mutable_instance().Push(db);
	}
	return count;
}

// 查找记录
bool AlarmService::FindPage(int pageIndex, int pageSize, std::vector<AlarmInfo>& list)
{
	IDbBasePtr db = DBPoll::get_mutable_instance().Pop();
	if (db)
	{
		std::string sql = boost::str(boost::format(SQL_QUERY_ALARM_PAGE));
		sql += boost::str(boost::format(" limit %d, %d") % pageIndex % pageSize);
		bool ret = db->Query(sql.c_str());
		if (ret)
		{
			while (db->FetchNextRow())
			{
				AlarmInfo item;
				ToRecord(db, item);
				list.push_back(item);
			}
			db->FreeQueryResult();
		}
		DBPoll::get_mutable_instance().Push(db);
		return ret;
	}
	return false;
}

bool AlarmService::FindByDevice(int pageIndex, int pageSize, std::string deviceId, std::vector<AlarmInfo>& list)
{
	IDbBasePtr db = DBPoll::get_mutable_instance().Pop();
	if (db)
	{
		std::string sql = boost::str(boost::format(SQL_QUERY_ALARM_PAGE));
		if (!deviceId.empty())
		{
			sql += boost::str(boost::format(" and `deviceId`='%s'") % deviceId);
		}
		sql += boost::str(boost::format(" limit %d, %d") % pageIndex % pageSize);
		bool ret = db->Query(sql.c_str());
		if (ret)
		{
			while (db->FetchNextRow())
			{
				AlarmInfo item;
				ToRecord(db, item);
				list.push_back(item);
			}
			db->FreeQueryResult();
		}
		DBPoll::get_mutable_instance().Push(db);
		return ret;
	}
	return false;
}

bool AlarmService::FindPast(int pageIndex, int pageSize, std::string lastTime, std::vector<AlarmInfo>& list)
{
	IDbBasePtr db = DBPoll::get_mutable_instance().Pop();
	if (db)
	{
		std::string sql = boost::str(boost::format(SQL_QUERY_ALARM_PAGE));
		if (!lastTime.empty())
		{
			sql += boost::str(boost::format(" and `alarmTime` <= '%s'") % lastTime);
		}
		sql += boost::str(boost::format(" limit %d, %d") % pageIndex % pageSize);
		bool ret = db->Query(sql.c_str());
		if (ret)
		{
			while (db->FetchNextRow())
			{
				AlarmInfo item;
				ToRecord(db, item);
				list.push_back(item);
			}
			db->FreeQueryResult();
		}
		DBPoll::get_mutable_instance().Push(db);
		return ret;
	}
	return false;
}

bool AlarmService::FindLatest(int pageIndex, int pageSize, std::vector<AlarmInfo>& list)
{
	IDbBasePtr db = DBPoll::get_mutable_instance().Pop();
	if (db)
	{
		std::string sql = boost::str(boost::format(SQL_QUERY_ALARM_PAGE));
		sql += boost::str(boost::format(" and `upload` = 0"));
		sql += boost::str(boost::format(" order by `alarmTime` desc"));
		sql += boost::str(boost::format(" limit %d, %d") % pageIndex % pageSize);
		bool ret = db->Query(sql.c_str());
		if (ret)
		{
			while (db->FetchNextRow())
			{
				AlarmInfo item;
				ToRecord(db, item);
				list.push_back(item);
			}
			db->FreeQueryResult();
		}
		DBPoll::get_mutable_instance().Push(db);
		return ret;
	}
	return false;
}

bool AlarmService::FindAlarmRecord(int pageIndex, int pageSize, std::vector<AlarmInfo>& list)
{
	IDbBasePtr db = DBPoll::get_mutable_instance().Pop();
	if (db)
	{
		std::string sql = boost::str(boost::format(SQL_QUERY_ALARM_PAGE));
		sql += boost::str(boost::format(" and `upload` = 1"));
		sql += boost::str(boost::format(" and `uploadRecord` = 0"));
		sql += boost::str(boost::format(" and `recordPath` is not null"));
		sql += boost::str(boost::format(" order by `alarmTime` desc"));
		sql += boost::str(boost::format(" limit %d, %d") % pageIndex % pageSize);
		bool ret = db->Query(sql.c_str());
		if (ret)
		{
			while (db->FetchNextRow())
			{
				AlarmInfo item;
				ToRecord(db, item);
				list.push_back(item);
			}
			db->FreeQueryResult();
		}
		DBPoll::get_mutable_instance().Push(db);
		return ret;
	}
	return false;
}

bool AlarmService::FindPage(int pageIndex, int pageSize,
	std::string deviceId, std::string startTime,
	std::string endTime, std::string alarmType,
	std::string upload, std::vector<AlarmInfo>& list)
{
	IDbBasePtr db = DBPoll::get_mutable_instance().Pop();
	if (db)
	{
		std::string sql = boost::str(boost::format(SQL_QUERY_ALARM_PAGE));
		if (!deviceId.empty())
		{
			sql += boost::str(boost::format(" and `deviceId`='%s'") % deviceId);
		}
		if (!startTime.empty() && !endTime.empty())
		{
			sql += boost::str(boost::format(" and `alarmTime` between '%s' and '%s'") % startTime % endTime);
		}
		if (!alarmType.empty())
		{
			sql += boost::str(boost::format(" and `alarmType`='%s'") % alarmType);
		}
		if (!upload.empty())
		{
			sql += boost::str(boost::format(" and `upload`=%s") % upload);
		}
		sql += boost::str(boost::format(" order by `alarmTime` desc"));
		sql += boost::str(boost::format(" limit %d, %d") % pageIndex % pageSize);
		bool ret = db->Query(sql.c_str());
		if (ret)
		{
			while (db->FetchNextRow())
			{
				AlarmInfo item;
				ToRecord(db, item);
				list.push_back(item);
			}
			db->FreeQueryResult();
		}
		DBPoll::get_mutable_instance().Push(db);
		return ret;
	}
	return false;
}

bool AlarmService::Find(AlarmInfo& item)
{
	IDbBasePtr db = DBPoll::get_mutable_instance().Pop();
	if (db)
	{
		std::string sql = boost::str(boost::format(SQL_QUERY_ALARM) % item.GetId());
		bool ret = db->Query(sql.c_str());
		if (ret)
		{
			ret = false;
			if (db->FetchNextRow())
			{
				ToRecord(db, item);
				ret = true;
			}
			db->FreeQueryResult();
		}
		DBPoll::get_mutable_instance().Push(db);
		return ret;
	}
	return false;
}

bool AlarmService::Update(AlarmInfo& item)
{
	IDbBasePtr db = DBPoll::get_mutable_instance().Pop();
	if (db)
	{
		std::string sql = boost::str(boost::format(SQL_UPDATE_ALARM)
			% item.GetRecordPath()
			% item.GetRecordUrl()
			% item.GetId());
		bool ret = db->Update(sql.c_str());
		DBPoll::get_mutable_instance().Push(db);
		return ret;
	}
	return false;
}

bool AlarmService::Upload(AlarmInfo& item)
{
	IDbBasePtr db = DBPoll::get_mutable_instance().Pop();
	if (db)
	{
		DateTime dt = DateTime::Now();
		std::string sql = boost::str(boost::format(SQL_ALARM_UPLOAD)
			% dt.ToNormalString()
			% item.GetId());
		bool ret = db->Update(sql.c_str());
		DBPoll::get_mutable_instance().Push(db);
		return ret;
	}
	return false;
}

void AlarmService::ToRecord(IDbBasePtr db, AlarmInfo& item)
{
	std::string id = "";
	if (db->GetColValue(0))
	{
		id = db->GetColValue(0);
	}
	std::string deviceId = "";
	if (db->GetColValue(1))
	{
		deviceId = db->GetColValue(1);
	}
	std::string deviceName = "";
	if (db->GetColValue(2))
	{
		deviceName = db->GetColValue(2);
	}
	std::string alarmTime = "";
	if (db->GetColValue(3))
	{
		alarmTime = db->GetColValue(3);
	}
	std::string alarmType = "";
	if (db->GetColValue(4))
	{
		alarmType = db->GetColValue(4);
	}
	std::string alarmInfo = "";
	if (db->GetColValue(5))
	{
		alarmInfo = db->GetColValue(5);
	}
	int count = 0;
	if (db->GetColValue(6))
	{
		count = atoi(db->GetColValue(6));
	}
	int upload = 0;
	if (db->GetColValue(7))
	{
		upload = atoi(db->GetColValue(7));
	}
	std::string uploadTime = "";
	if (db->GetColValue(8))
	{
		uploadTime = db->GetColValue(8);
	}
	int uploadCount = 0;
	if (db->GetColValue(9))
	{
		uploadCount = atoi(db->GetColValue(9));
	}
	std::string imagePath = "";
	if (db->GetColValue(10))
	{
		imagePath = db->GetColValue(10);
	}
	std::string imageUrl = "";
	if (db->GetColValue(11))
	{
		imageUrl = db->GetColValue(11);
	}
	int uploadRecord = 0;
	if (db->GetColValue(12))
	{
		uploadRecord = atoi(db->GetColValue(12));
	}
	std::string recordPath = "";
	if (db->GetColValue(13))
	{
		recordPath = db->GetColValue(13);
	}
	std::string recordUrl = "";
	if (db->GetColValue(14))
	{
		recordUrl = db->GetColValue(14);
	}

	item.SetId(id);
	item.SetDeviceId(deviceId);
	item.SetDeviceName(deviceName);
	item.SetAlarmType(alarmType);
	item.SetAlarmInfo(alarmInfo);
	item.SetCount(count);

	DateTime alarm_time;
	alarm_time.From(alarmTime);
	item.SetAlarmTime(alarm_time);

	item.SetUpload(upload);

	DateTime upload_time;
	upload_time.From(uploadTime);
	item.SetUploadTime(upload_time);

	item.SetUploadCount(uploadCount);
	item.SetImagePath(imagePath);
	item.SetImageUrl(imageUrl);
	item.SetUploadRecord(uploadRecord);
	item.SetRecordPath(recordPath);
	item.SetRecordUrl(recordUrl);
}
